//	HyperText Access method manager Object			HyperManager.m
//	--------------------------------------
//
//	It is the job of a hypermanager to keep track of all the HyperAccess modules
//	which exist, and to pass on to the right one a general request.
//
// History:
//	   Oct 90	Written TBL
//
#define NextStep	/* Control HText.h */

#define HELP_ENTRY "http://info.cern.ch/hypertext/WWW/NextStep/WorldWideWeb.html"

#import "HyperManager.h"

#import "HyperText.h"

#import "HText.h"
#import "HTUtils.h"
#import "HTParse.h"
#import "HTAccess.h"
#import "HTHistory.h"
#import "HTAlert.h"

@implementation HyperManager 

#import "WWWPageLayout.h"

#define THIS_TEXT  (HyperText *)[[[NXApp mainWindow] contentView] docView]

extern char * WWW_nameOfFile(const char * name);	/* In file access */

/*	Exported to everyone */

int WWW_TraceFlag;	/* Exported to everyone */
char * appDirectory;	/* Name of the directory containing the application */

PUBLIC HyperAccess* TheManager;

+ new
{
    self = [super new];
    accesses = [List new];		// Create and clear list
    TheManager = self;			// For text object sto find 
    return self;
}

- traceOn:sender { WWW_TraceFlag = 1; return self;}
- traceOff:sender { WWW_TraceFlag = 0; return self;}

- (const char *) name
{
    return "any";
}

//			Access Management functions
//


//	Load an anchor				loadAnchor:
//	--------------
//
//	It checks whether in fact the anchor
//	is already loaded and linked, and that the address string is not null.
//
// On exit:
//	If a duplicate node is found, that anchor is returned
//	If there is no success, nil is returned.
//	Otherwise, the anchor is returned.

- loadAnchor:(HTAnchor *)anAnchor Diagnostic:(int)diagnostic
{

    HText * HT;
    if (!HTLoadAnchor(anAnchor)) return nil;

    //	The node may have become an index: update the existence
    //   state of the panel.
    
    HT = (HText*) HTAnchor_document(HTAnchor_parent(anAnchor));
    if (HTAnchor_isIndex([HT nodeAnchor])) {
	[[keywords window] makeKeyAndOrderFront:self];
    } else {
	[[keywords window] close];
//		[[keywords window] orderOut:self];    @@ bug?
    }
    return self;
}

//______________________________________________________________________________


//	Open or search  by name
//	-----------------------
//
//	@@@ diagnostcics lost
//
- accessName:(const char *)arg
	Diagnostic:(int)diagnostic
{
    return HTLoadAbsolute(arg) ? self : nil;
}


//	Search with a given diagnostic level
//
//	This involves making a special address string, being the index address
//	with a ? sign followed by a "+" separated list of keywords.
//
- searchDiagnostic:(int)diagnostic
{

    HyperText * HT = THIS_TEXT;
    if (!HT) return nil;
    
    HTSearch([keywords stringValueAt:0], [HT nodeAnchor]);
    return self;

#ifdef OLD_CODE
    char keys[256];
    char *p, *q, *addr;
	...
    addr = HTAnchor_address((HTAnchor*)[HT nodeAnchor]);
    if ((p=strchr(addr, '?'))!=0) *p=0;	/* Chop off existing search string */   
    strcat(addr,"?");
    strcpy(keys, [keywords stringValueAt:0]);
    q =HTStrip(keys);			/* Strip leading and trailing */
    for(p=q; *p; p++)
        if (WHITE(*p)) {
	    *p='+';			/* Separate with plus signs */
	    while (WHITE(p[1])) p++;	/* Skip multiple blanks */
	    if (p[1]==0) *p = 0;	/* Chop a single trailing space */
        }
    StrAllocCat(addr, keys);			/* Make combined node name */
    {
    	id status = [self accessName:HTStrip(addr) Diagnostic:diagnostic];
    	free(addr);
    	return status;
    }
#endif

}

//				N A V I G A T I O N


//	Relative moves
//	--------------
//
//	These navigate around the web as though it were a tree, from the point of
//	view of the user's browsing order.

- back:sender		{ HTLoadAnchor(HTHistory_backtrack()); return self; }
- next:sender		{ HTLoadAnchor(HTHistory_next); return self; }
- previous:sender	{ HTLoadAnchor(HTHistory_previous); return self; }


//	Go Home
//	-------
//
//	This accesses the default page of text for the user or, failing that,
//	for the system. 
//
static HTParentAnchor * home = NULL;
- goHome:sender
{
    if (!home) home = HTHomeAnchor();
    return HTLoadAnchor((HTAnchor*)home) ? self : nil;
}

//	Load Help information
//	---------------------
//
//
- help:sender
{
    return HTLoadAbsolute(HELP_ENTRY) ? self : nil;
}

//	Go to the Blank Page
//	--------------------
//
//
- goToBlank:sender
{
    // return [fileAccess openMy:"blank.html" diagnostic:0];
    return nil;
}

//				Application Delegate Methods
//				============================


//	On Initialisation, Load Initial File
//	------------------------------------

-appDidInit:sender
{
    if (TRACE) printf("HyperManager: appDidInit\n");
    
//    StrAllocCopy(appDirectory, NXArgv[0]);
//    if (p = strrchr(appDirectory, '/')) p[1]=0;	/* Chop home slash */
//    if (TRACE) printf("WWW: Run from %s\n", appDirectory);
    
    return [self goHome:self];
}

//	Accept that we can open files from the workspace

- (BOOL)appAcceptsAnotherFile:sender
{
    return YES;
}

//	Open file from the Workspace
//
- (int)appOpenFile:(const char *)filename type:(const char *)aType
{
    char * name = WWW_nameOfFile(filename);
    HyperText * HT = [self accessName:name Diagnostic:0];
    free(name);
    return (HT!=0);
}

//	Open Temporary file
//
//	@@ Should unlink(2) the file when we have done with it!

- (int)appOpenTempFile:(const char *)filename type:(const char *)aType
{
    char * name = WWW_nameOfFile(filename);	/* No host */
    HyperText * HT = [self accessName:name Diagnostic:0];
    free(name);
    return (HT!=0);
}



//		Actions:
//		-------
- search:sender
{
    return [self searchDiagnostic:0];
}

- searchRTF:sender
{
    return [self searchDiagnostic:1];
}

- searchSGML:sender
{
    return [self searchDiagnostic:2];
}


//	Direct open buttons:

- open:sender
{
    return [self accessName:[openString stringValueAt:0] Diagnostic:0];
}

- (HTChildAnchor *) linkToString:sender
{
    return [THIS_TEXT linkSelTo:
        	HTAnchor_findAddress([openString stringValueAt:0])
	   ];
}

- openRTF:sender
{
 return [self accessName:[openString stringValueAt:0] Diagnostic:1];
}

- openSGML:sender
{
 return [self accessName:[openString stringValueAt:0] Diagnostic:2];
}


//	Save a document
//	---------------
- save:sender
{
    HyperText * HT = THIS_TEXT;
    
    if (YES) {
        HTParentAnchor * anchor = [HT nodeAnchor];
    	HTStream * s = HTSaveStream(anchor);
	char * addr;
	if (!s) return nil;
	
	addr = HTAnchor_address((HTAnchor*)anchor); //	The WWW address
        if ([HT writeSGML:s relativeTo:addr])
		[[HT window] setDocEdited:NO];
        free(addr);
    } else {
    	HTAlert("Can only save HTML format");
	return nil;
    }
#ifdef NOT_YET
    else if (format==WWW_RICHTEXT) [HT writeRichText:s];
    else if (format==WWW_PLAINTEXT || format==WWW_SOURCE) [HT writeText:s];
    else fprintf(stderr, "HT/File: Unknown format!\n");
#endif    

    return self;		/* OK */
}

//	Save all hypertexts back
//	-------------------------

- saveAll:sender
{
    List * windows = [NXApp windowList];
    id cv;
    int i;
    int n = [windows count];
    
    for(i=0; i<n ; i++){
	Window * w = [windows objectAt:i];
	if (cv=[w contentView])
	 if ([cv respondsTo:@selector(docView)])
	 if ([w isDocEdited]) {
		HyperText * HT = [[w contentView] docView];
		if ([TheManager saveNode:HT])
			[w setDocEdited: NO];
	}
    }

    return self;
}


//	Close all unedited windows except this one
//	------------------------------------------
//

- closeOthers:sender
{
    Window * thisWindow = [NXApp mainWindow];
    List * windows = [[NXApp windowList] copy];

    {
        int i;
	id cv;					// Content view
	int n = [windows count];
        for(i=0; i<n; i++){
	    Window * w = [windows objectAt:i];
	    if (w != thisWindow)
	    if (cv=[w contentView])
	    if ([cv respondsTo:@selector(docView)]) {
	    	if (![w isDocEdited]) {
		    if (TRACE) printf(" Closing window %p\n", (void*)w);
		    [w performClose:self];
	        }
	    }
	}
	[windows free];				/* Free off copy of list */
	return self;
    }
}

//	Print Postscript code for the main window
//	-----------------------------------------

- print:sender
{
     return [THIS_TEXT printPSCode:sender];
}

//	Run the page layout panel
//
- runPagelayout:sender
{
    PageLayout * pl = [WWWPageLayout new];
    [pl runModal];
    return self;
}

//	Set the title of the main window
//	--------------------------------

- setDocTitle: sender
{
    Window * thisWindow = [NXApp mainWindow];
    [thisWindow setTitle:[titleString stringValueAt:0]];
    [thisWindow setDocEdited:YES];
    return self;
}

//	Inspect Link
//	------------

- inspectLink:sender
{
    HTChildAnchor * source = [THIS_TEXT selectedLink];
    HTAnchor * destination;
    if (!source){
    	[openString setStringValue: "(No anchor selected in main document.)"
                at:0];
         return nil;
    }
    {
    	char * source_address = HTAnchor_address((HTAnchor*)source);
    	[addressString setStringValue: source_address];
	free(source_address);
    }

    destination = HTAnchor_followMainLink((HTAnchor*)source);
    if (destination) {
    	char * destination_address = HTAnchor_address((HTAnchor*)destination);
    	[openString setStringValue: destination_address at:0];
	free(destination_address);
    } else {
	[openString setStringValue: "Anchor not linked."  at:0];
    }

    return self;
}

//	Copy address of document
//	------------------------
- copyAddress:sender
{
    char * addr = HTAnchor_address((HTAnchor*)[THIS_TEXT nodeAnchor]);
    [openString setStringValue:addr at:0];
    free(addr);
    return self;
}

//		HyperText delegate methods
//		==========================
//
//	This one has been passed from a window
//	to the hypertext which is its delegate,
//	to the access server module of that hypertext,
//	to this access manager.
//
// When a hypertext window becomes a key window, the search
// panel is turned on or off depending on whether a search can be done,
// and the default address in the "open using full reference" panel
// is set to the address of the current hypertext.
//
- hyperTextDidBecomeMain: sender
{

    HTParentAnchor * anchor = [(HText*)sender nodeAnchor];
    char * addr = HTAnchor_address((HTAnchor*)anchor);
    
    HTMainText = sender;		/* Record for HTAccess */
    HTMainAnchor = anchor;
    
    if (HTAnchor_isIndex([sender nodeAnchor])) {
        [[keywords window] makeKeyAndOrderFront:self];
    } else {
        [[keywords window] close];
//        [[keywords window] orderOut:self];	bug?
    }
    [titleString setStringValue: [[sender window] title] at:0];
    [addressString setStringValue: addr];
//  [openString setStringValue: addr at:0];
    free(addr);
    return self;
}

//	Panel delegate methods
//
//	The only windows to which this object is a delegate
//	are the open and search panels. When they become key,
//	we ensure that the text is selected.

- windowDidBecomeKey:sender
{
    if (sender == [openString window])
        [openString selectTextAt:0];	// Preselect the text
    else if (sender == [keywords window])
        [keywords selectTextAt:0];	// Preselect the text

    return self;
}
@end
